package com.compass.mobile.network.interceptor


import LogUtil
import UserInfoManager
import com.compass.mobile.framework.constant.LOGIN_FAILURE
import com.compass.mobile.framework.utils.LiveDataBus
import com.compass.mobile.network.manager.ApiManager
import com.compass.mobile.network.response.BaseResponse

import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
import okhttp3.Response
import okhttp3.ResponseBody

import java.util.concurrent.locks.ReentrantLock

/**
 * Description： token拦截器 ReentrantLock 写法待测试
 * Date:2023/12/16 19:55
 */
class  TokenInterceptor : Interceptor {


    @Volatile
    private var mRefreshInvalidTime = 0L

    @Volatile
    private var isRefreshToken = false
    private val mRefreshTokenLock by lazy { ReentrantLock() }
    private val gson: Gson by lazy { Gson() }


    override fun intercept(chain: Interceptor.Chain): Response {
        val response = chain.proceed(chain.request())

        if (response.code() != 200) {
            return response
        }

        response.body()?.let {
            try {
                val mediaType = it.contentType()
                val string = it.string()
                val responseBody = ResponseBody.create(mediaType,string)
                var apiResponse = gson.fromJson(string, BaseResponse::class.java)


                //401 token过期需要刷新 || 校验Token是否过期
                if (apiResponse.code == 401) {
                    return onTokenRefresh(chain, response) ?: kotlin.run { return response }
                }
                // 校验Token是否失效
                if (apiResponse.code == 406) {
                    this.onTokenInvalid(response)
                }

                return response.newBuilder().body(responseBody).build()
            } catch (ex: Exception) {
                return response
            }
        }
        return response
    }

    /**
     * Token 刷新
     */
    private fun onTokenRefresh(chain: Interceptor.Chain, response: Response): Response? {

        var newResponse: Response? = response
        try {
            if (!mRefreshTokenLock.isLocked) {//查询该锁是否被任何线程持有,如果有线程持有此锁，则为True，否则为false
                this.mRefreshTokenLock.lock()
                this.isRefreshToken = true
                runBlocking {
                    launch(Dispatchers.Default) {
                        newResponse = requestAuthToken(chain, response)
                    }
                }
                this.mRefreshTokenLock.unlock()
                this.isRefreshToken = false
            } else {
                while (true) {
                    if (!isRefreshToken) {
                        newResponse = doRequest(chain)
                        break
                    }
                }
            }
        } catch (e: Exception) {
            // do something
        } finally {
            if (mRefreshTokenLock.isLocked) {
                this.mRefreshTokenLock.unlock()
                this.isRefreshToken = false
            }
        }
        return newResponse
    }

    /**
     * Token 失效
     */
    private fun onTokenInvalid(response: Response) {
        // 防抖
        val currentTime = System.currentTimeMillis()
        if ((currentTime - mRefreshInvalidTime) > KET_TOKEN_INVALID_ANTI_SHAKE) {
            this.mRefreshInvalidTime = currentTime
            // 跳转登录页 or 自行逻辑
            LiveDataBus.get().with(LOGIN_FAILURE).postValue(LOGIN_FAILURE)
        }
    }


    /**
     * 请求 刷新Token
     */
    private fun requestAuthToken(chain: Interceptor.Chain, response: Response): Response? {
        LogUtil.e("http_data====刷新token")
        var newResponse: Response? = response
        val resp = ApiManager.api.refreshTokenFlow(UserInfoManager.getRefreshToken().toString())
            .execute() // 请求代码
        if (resp.isSuccessful) {
            response.close()
            resp.body()?.let { call ->
                if (call.code == 0) {
                    ////更新本地Token
                    LogUtil.e("http_data===保存最新token=${call.data?.accessToken}")
                    UserInfoManager.saveAccessToken(call.data?.accessToken)
                }
                newResponse = doRequest(chain)
            }

        }
        return newResponse
    }


    //创建新的请求
    private fun doRequest(chain: Interceptor.Chain): Response? {
        var response: Response?=null

        try {
            //使用新的Token，创建新的请求
            val newRequest = chain.request()
                .newBuilder()
                .header("Authorization", "Bearer ${UserInfoManager.getAccessToken()}")
                .build()
            //执行新的请求
            response = chain.proceed(newRequest)
        } catch (e: Exception) {
            // do something
        }
        return response
    }


    companion object {
        const val KET_TOKEN_INVALID_ANTI_SHAKE = 2000
    }
}